home *** CD-ROM | disk | FTP | other *** search
Text File | 2001-09-26 | 51.9 KB | 1,574 lines |
- *usr_41.txt* For Vim version 6.0. Last change: 2001 Sep 18
-
- VIM USER MANUAL - by Bram Moolenaar
-
- Write a Vim script
-
-
- The Vim script language is used for the startup vimrc file, syntax files, and
- many other things. This chapter explains the items that can be used in a Vim
- script. There are a lot of them, thus this is a long chapter.
-
- |41.1| Introduction
- |41.2| Variables
- |41.3| Expressions
- |41.4| Conditionals
- |41.5| Executing an expression
- |41.6| Using functions
- |41.7| Defining a function
- |41.8| Various remarks
- |41.9| Writing a plugin
- |41.10| Writing a filetype plugin
- |41.11| Writing a compiler plugin
-
- Next chapter: |usr_42.txt| Add new menus
- Previous chapter: |usr_40.txt| Make new commands
- Table of contents: |usr_toc.txt|
-
- ==============================================================================
- *41.1* Introduction *vimrc-intro* *vim-script-intro*
-
- Your first experience with Vim scripts is the vimrc file. Vim reads it when
- it starts up and executes the commands. You can set options to values you
- prefer. And you can use any colon command in it (commands that start with a
- ":"; these are sometimes referred to as Ex commands or command-line commands).
- Syntax files are also Vim scripts. As are files that set options for a
- specific file type. A complicated macro can be defined by a separate Vim
- script file. You can think of other uses yourself.
-
- Let's start with a simple example: >
-
- :let i = 1
- :while i < 5
- : echo "count is" i
- : let i = i + 1
- :endwhile
- <
- Note:
- The ":" characters are not really needed here. You only need to use
- them when you type a command. In a Vim script file they can be left
- out. We will use them here anyway to make clear these are colon
- commands and make them stand out from Normal mode commands.
-
- The ":let" command assigns a value to a variable. The generic form is: >
-
- :let {variable} = {expression}
-
- In this case the variable name is "i" and the expression is a simple value,
- the number one.
- The ":while" command starts a loop. The generic form is: >
-
- :while {condition}
- : {statements}
- :endwhile
-
- The statements until the matching ":endwhile" are executed for as long as the
- condition is true. The condition used here is the expression "i < 5". This
- is true when the variable i is smaller than five.
- The ":echo" command prints its arguments. In this case the string "count
- is" and the value of the variable i. Since i is one, this will print:
-
- count is 1 ~
-
- Then there is another ":let i =" command. The value used is the expression "i
- + 1". This adds one to the variable i and assigns the new value to the same
- variable.
- The output of the example code is:
-
- count is 1 ~
- count is 2 ~
- count is 3 ~
- count is 4 ~
-
- Note:
- If you happen to write a while loop that keeps on running, you can
- interrupt it by pressing CTRL-C (CTRL-Break on MS-Windows).
-
-
- THREE KINDS OF NUMBERS
-
- Numbers can be decimal, hexadecimal or octal. A hexadecimal number starts
- with "0x" or "0X". For example "0x1f" is 31. An octal number starts with a
- zero. "017" is 15. Careful: don't put a zero before a decimal number, it
- will be intepreted as an octal number!
- The ":echo" command always prints decimal numbers. Example: >
-
- :echo 0x7f 036
- < 127 30 ~
-
- A number is made negative with a minus sign. This also works for hexadecimal
- and octal numbers. A minus sign is also for substraction. Compare this with
- the previous example: >
-
- :echo 0x7f -036
- < 97 ~
-
- White space in an expression is ignored. However, it's recommended to use it
- for separating items, to make the expression easier to read. For example, to
- avoid the confusion with a negative number, put a space between the minus sign
- and the following number: >
-
- :echo 0x7f - 036
-
- ==============================================================================
- *41.2* Variables
-
- A variable name consists of ASCII letters, digits and the underscore. It
- cannot start with a digit. Valid variable names are:
-
- counter
- _aap3
- very_long_variable_name_with_dashes
- FuncLength
- LENGTH
-
- Invalid names are "foo+bar" and "6var".
- These variables are global. To see a list of currently defined variables
- use this command: >
-
- :let
-
- You can use global variables everywhere. This also means that when the
- variable "count" is used in one script file, it might also be used in another
- file. This leads to confusion at least, and real problems at worst. To avoid
- this, you can use a variable local to a script file by prepending "s:". For
- example, one script contains this code: >
-
- :let s:count = 1
- :while s:count < 5
- : source other.vim
- : let s:count = s:count + 1
- :endwhile
-
- Since "s:count" is local to this script, you can be sure that sourcing the
- "other.vim" script will not change this variable. If "other.vim" also uses an
- "s:count" variable, it will be a different copy, local to that script. More
- about script-local variables here: |script-variable|.
-
- There are more kinds of variables, see |internal-variables|. The most often
- used ones are:
-
- b:name variable local to a buffer
- w:name variable local to a window
- g:name global variable (also in a function)
- v:name variable predefined by Vim
-
-
- DELETING VARIABLES
-
- Variables take up memory and show up in the output of the ":let" command. To
- delete a variable use the ":unlet" command. Example: >
-
- :unlet s:count
-
- This deletes the script-local variable "s:count" to free up the memory it
- uses. If you are not sure if the variable exists, and don't want an error
- message when it doesn't, append !: >
-
- :unlet! s:count
-
- When a script finishes, the local variables used there will not be
- automatically freed. The next time the script executes, it can still use the
- old value. Example: >
-
- :if !exists("s:call_count")
- : let s:call_count = 0
- :endif
- :let s:call_count = s:call_count + 1
- :echo "called" s:call_count "times"
-
- The "exists()" function checks if a variable has already been defined. Its
- argument is the name of the variable you want to check. Not the variable
- itself! If you would do this: >
-
- :if !exists(s:call_count)
-
- Then the value of s:call_count will be used as the name of the variable that
- exists() checks. That's not what you want.
- The exclamation mark ! negates a value. When the value was true, it
- becomes false. When it was false, it becomes true. You can read it as "not".
- Thus "if !exists()" can be read as "if not exists()".
- What Vim calls true is anything that is not zero. Only zero is false.
-
-
- STRING VARIABLES AND CONSTANTS
-
- So far only numbers were used for the variable value. Strings can be used as
- well. Numbers and strings are the only two types of variables that Vim
- supports. The type is dynamic, it is set each time when assigning a value to
- the variable with ":let".
- To assign a string value to a variable, you need to use a string constant.
- There are two types of these. First the string in double quotes: >
-
- :let name = "peter"
- :echo name
- < peter ~
-
- If you want to include a double quote inside the string, put a backslash in
- front of it: >
-
- :let name = "\"peter\""
- :echo name
- < "peter" ~
-
- To avoid the need for a backslash, you can use a string in single quotes: >
-
- :let name = '"peter"'
- :echo name
- < "peter" ~
-
- Inside a single-quote string all the characters are taken literally. The
- drawback is that it's impossible to include a single quote. A backslash is
- taken literally as well, thus you can't use it to change the meaning of the
- character after it.
- In double-quote strings it is possible to use special characters. Here are
- a few useful ones:
-
- \t <Tab>
- \n <NL>, line break
- \r <CR>, <Enter>
- \e <Esc>
- \b <BS>, backspace
- \" "
- \\ \, backslash
- \<Esc> <Esc>
- \<C-W> CTRL-W
-
- The last two are just examples. The "\<name>" form can be used to include
- the special key "name".
- See |expr-quote| for the full list of special items in a string.
-
- ==============================================================================
- *41.3* Expressions
-
- Vim has a rich, yet simple way to handle expressions. You can read the
- definition here: |expression-syntax|. Here we will show the most common
- items.
- The numbers, strings and variables mentioned above are expressions by
- themselves. Thus everywhere an expression is expected, you can use a number,
- string or variable. Other basic items in an expression are:
-
- $NAME environment variable
- &name option
- @r register
-
- Examples: >
-
- :echo "The value of 'tabstop' is" &ts
- :echo "Your home directory is" $HOME
- :if @a > 5
-
- The &option form can be used to save an option value, set it to a new value,
- do something and restore the old value. Example: >
-
- :let save_ic = &ic
- :set noic
- :/The Start/,$delete
- :let &ic = save_ic
-
- This makes sure the "The Start" pattern is used with the 'ignorecase' option
- off. Still, it keeps the value that the user had set.
-
-
- MATHEMATICS
-
- It becomes more interesting if we combine these basic items. Let's start with
- mathematics on numbers:
-
- a + b add
- a - b subtract
- a * b multiply
- a / b divide
- a % b modulo
-
- The usual precedence is used. Example: >
-
- :echo 10 + 5 * 2
- < 20 ~
-
- Grouping is done with braces. No suprises here. Example: >
-
- :echo (10 + 5) * 2
- < 30 ~
-
- Strings can be concatenated with ".". Example: >
-
- :echo "foo" . "bar"
- < foobar ~
-
- When the ":echo" command gets multiple arguments, it separates them with a
- space. In the example the argument is a single expression, thus no space is
- inserted.
-
- Borrowed from the C language is the conditional expression:
-
- a ? b : c
-
- If "a" evaluates to true "b" is used, otherwise "c" is used. Example: >
-
- :let i = 4
- :echo i > 5 ? "i is big" : "i is small"
- < i is small ~
-
- The three parts of the constructs are always evaluated first, thus you could
- see it work as:
-
- (a) ? (b) : (c)
-
- ==============================================================================
- *41.4* Conditionals
-
- The ":if" commands executes the following statements, until the matching
- ":endif", only when a condition is met. The generic form is:
-
- :if {condition}
- {statements}
- :endif
-
- Only when the expression {condition} evaluates to true (non-zero) will the
- {statements} be executed. These must still be valid commands. If they
- contain garbage, Vim won't be able to find the ":endif".
- You can also use ":else". The generic form for this is:
-
- :if {condition}
- {statements}
- :else
- {statements}
- :endif
-
- The second {statements} is only executed if the first one isn't.
- Finally, there is ":elseif":
-
- :if {condition}
- {statements}
- :elseif {condition}
- {statements}
- :endif
-
- This works just like using ":else" and then "if", but without the need for an
- extra ":endif".
- A useful example for your vimrc file is checking the 'term' option and
- doing something depending upon its value: >
-
- :if &term == "xterm"
- : " Do stuff for xterm
- :elseif &term == "vt100"
- : " Do stuff for a vt100 terminal
- :else
- : " Do something for other terminals
- :endif
-
-
- LOGIC OPERATIONS
-
- We already used some of them in the examples. These are the most often used
- ones:
-
- a == b equal to
- a != b not equal to
- a > b greater than
- a >= b greater than or equal to
- a < b less than
- a <= b less than or equal to
-
- The result is one if the condition is met and zero otherwise. An example: >
-
- :if v:version >= 600
- : echo "congratulations"
- :else
- : echo "you are using an old version, upgrade!"
- :endif
-
- Here "v:version" is a variable defined by Vim, which has the value of the Vim
- version. 600 is for version 6.0. Version 6.1 will have the value 601.
- This is very useful to write a script that works with multiple versions of
- Vim. |v:version|
-
- The logic operators work both for numbers and strings. When comparing two
- strings, the mathematical difference is used. This compares byte values,
- which may not be right for some languages.
- When comparing a string with a number, the string is first converted to a
- number. This is a bit tricky, because when a string doesn't look like a
- number, the number zero is used. Example: >
-
- :if 0 == "one"
- : echo "yes"
- :endif
-
- This will echo "yes", because "one" doesn't look like a number, thus it is
- converted to the number zero.
-
- For strings there are two more items:
-
- a =~ b matches with
- a !~ b does not match with
-
- The left item "a" is used as a string. The right item "b" is used as a
- pattern, like what's used for searching. Example: >
-
- :if str =~ " "
- : echo "str contains a space"
- :elseif str !~ '\.$'
- : echo "str ends in a full stop"
- :endif
-
- Notice the use of a single-quote string for the pattern. This is useful,
- because backslashes need to be doubled in a double-quote string and patterns
- tend to contain many backslashes.
-
- The 'ignorecase' option is used when comparing strings. When you don't want
- that, append "#" to match case and "?" to ignore case. Thus "==?" compares
- two strings to be equal while ignoring case. And "!~#" checks if a pattern
- doesn't match, also checking the case of letters. For the full table see
- |expr-==|.
-
-
- MORE LOOPING
-
- The ":while" command was already mentioned. Two more statements can be used
- in between the ":while" and the ":endwhile":
-
- :continue Jump back to the start of the while loop; the
- loop continues.
- :break Jump forward to the ":endwhile"; the loop is
- discontinued.
-
- Example: >
-
- :while counter < 40
- : call do_something()
- : if skip_flag
- : continue
- : endif
- : if finished_flag
- : break
- : endif
- : sleep 50m
- :endwhile
-
- The ":sleep" command makes Vim take a nap. The "50m" specifies fifty
- milliseconds. Another example is ":sleep 4", which sleeps for four seconds.
-
- ==============================================================================
- *41.5* Executing an expression
-
- So far the commands in the script were executed by Vim directly. The
- ":execute" command allows executing the result of an expression. This is a
- very powerful way to build commands and execute them.
- An example is to jump to a tag, which is contained in a variable: >
-
- :execute "tag " . tag_name
-
- The "." is used to concatenate the string "tag " with the value of variable
- "tag_name". Suppose "tag_name" has the value "get_cmd", then the command that
- will be executed is: >
-
- :tag get_cmd
-
- The ":execute" command can only execute colon commands. The ":normal" command
- executes Normal mode commands. However, its argument is not an expression but
- the literal command characters. Example: >
-
- :normal gg=G
-
- This jumps to the first line and formats all lines with the "=" operator.
- To make ":normal" work with an expression, combine ":execute" with it.
- Example: >
-
- :execute "normal " . normal_commands
-
- The variable "normal_commands" must contain the Normal mode commands.
- Make sure that the argument for ":normal" is a complete command. Otherwise
- Vim will run into the end of the argument and abort the command. For example,
- if you start Insert mode, you must leave Insert mode as well. This works: >
-
- :execute "normal Inew text \<Esc>"
-
- This inserts "new text " in the current line. Notice the use of the special
- key "\<Esc>". This avoids having to enter a real <Esc> character in your
- script.
-
- ==============================================================================
- *41.6* Using functions
-
- Vim defines many functions and provides a large amount of functionality that
- way. A few examples will be given in this section. You can find the whole
- list here: |functions|.
-
- A function is called with the ":call" command. The parameters are passed in
- between braces, separated by commas. Example: >
-
- :call search("Date: ", "W")
-
- This calls the search() function, with arguments "Date: " and "W". The
- search() function uses its first argument as a search pattern and the second
- one as flags. The "W" flag means the search doesn't wrap around the end of
- the file.
-
- A function can be called in an expression. Example: >
-
- :let line = getline(".")
- :let repl = substitute(line, '\a', "*", "g")
- :call setline(".", repl)
-
- The getline() function obtains a line from the current file. Its argument is
- a specification of the line number. In this case "." is used, which means the
- line where the cursor.
- The substitute() function does something similar to the ":substitute"
- command. The first argument is the string on which to perform the
- substitution. The second argument is the pattern, the third the replacement
- string. Finally, the last arguments are the flags.
- The setline() function sets the line, specified by the first argument, to a
- new string, the second argument. In this example the line under the cursor is
- replaced with the result of the substitute(). Thus the effect of the three
- statements is equal to: >
-
- :substitute/\a/*/g
-
- Using the functions becomes more interesting when you do more work before and
- after the substitute() call.
-
-
- FUNCTIONS *function-list*
-
- There are many functions. We will mention them here, grouped by what they are
- used for. You can find an alphabetical list here: |functions|. Use CTRL-] on
- the function name to jump to detailed help on it.
-
- String manipulation:
- char2nr() get ASCII value of a character
- nr2char() get a character by its ASCII value
- escape() escape characters in a string with a '\'
- strtrans() translate a string to make it printable
- tolower() turn a string to lowercase
- toupper() turn a string to uppercase
- match() position where a pattern matches in a string
- matchend() position where a pattern match ends in a string
- matchstr() match of a pattern in a string
- stridx() first index of a short string in a long string
- strridx() last index of a short string in a long string
- strlen() length of a string
- substitute() substitute a pattern match with a string
- submatch() get a specific match in a ":substitute"
- strpart() get part of a string
- expand() expand special keywords
- type() type of a variable
-
- Working with text in the current buffer:
- byte2line() get line number at a specific byte count
- line2byte() byte count at a specific line
- col() column number of the cursor or a mark
- virtcol() screen column of the cursor or a mark
- line() line number of the cursor or mark
- wincol() window column number of the cursor
- winline() window line number of the cursor
- getline() get a line from the buffer
- setline() replace a line in the buffer
- append() append {string} below line {lnum}
- indent() indent of a specific line
- cindent() indent according to C indenting
- lispindent() indent according to Lisp indenting
- nextnonblank() find next non-blank line
- prevnonblank() find previous non-blank line
- search() find a match for a pattern
- searchpair() find the other end of a start/skip/end
-
- System functions and manipulation of files:
- browse() put up a file requester
- glob() expand wildcards
- globpath() expand wildcards in a number of directories
- resolve() find out where a shortcut points to
- fnamemodify() modify a file name
- executable() check if an executable program exists
- filereadable() check if a file can be read
- isdirectory() check if a directory exists
- getcwd() get the current working directory
- getfsize() get the size of a file
- getftime() get last modification time of a file
- localtime() get current time
- strftime() convert time to a string
- tempname() get the name of a temporary file
- delete() delete a file
- rename() rename a file
- system() get the result of a shell command
- hostname() name of the system
-
- Buffers, windows and the argument list:
- argc() number of entries in the argument list
- argidx() current position in the argument list
- argv() get one entry from the argument list
- bufexists() check if a buffer exists
- buflisted() check if a buffer exists and is listed
- bufloaded() check if a buffer exists and is loaded
- bufname() get the name of a specific buffer
- bufnr() get the buffer number of a specific buffer
- winnr() get the window number for the current window
- bufwinnr() get the window number of a specific buffer
- winbufnr() get the buffer number of a specific window
- getbufvar() get a variable value from a specific buffer
- setbufvar() set a variable in a specific buffer
- getwinvar() get a variable value from a specific window
- setwinvar() set a variable in a specific buffer
-
- Folding:
- foldclosed() check for a closed fold at a specific line
- foldlevel() check for the fold level at a specific line
- foldtext() generate the line displayed for a closed fold
-
- Syntax highlighting:
- hlexists() check if a highlight group exists
- hlID() get ID of a highlight group
- synID() get syntax ID at a specific position
- synIDattr() get a specific attribute of a syntax ID
- synIDtrans() get translated syntax ID
-
- History:
- histadd() add an item to a history
- histdel() delete an item from a history
- histget() get an item from a history
- histnr() get highest index of a history list
-
- Interactive:
- confirm() let the user make a choice
- getchar() get a character from the user
- getcharmod() get modifiers for the last typed character
- input() get a line from the user
- inputsecret() get a line from the user without showing it
- inputdialog() get a line from the user in a dialog
-
- Vim server:
- serverlist() return the list of server names
- remote_send() send command characters to a Vim server
- remote_expr() evaluate an expression in a Vim server
- server2client() send a reply to a client of a Vim server
- remote_peek() check if there is a reply from a Vim server
- remote_read() read a reply from a Vim server
- foreground() move the Vim window to the foreground
- remote_foreground() move the Vim server window to the foreground
-
- Various:
- mode() get current editing mode
- visualmode() last visual mode used
- hasmapto() check if a mapping exists
- mapcheck() check if a matching mapping exists
- maparg() get rhs of a mapping
- exists() check if a variable, function, etc. exists
- has() check if a feature is supported in Vim
- cscope_connection() check if a cscope connection exists
- did_filetype() check if a FileType autocommand was used
- eventhandler() check if invoked by an event handler
- getwinposx() X position of the GUI Vim window
- getwinposy() Y position of the GUI Vim window
- winheight() get height of a specific window
- winwidth() get width of a specific window
- libcall() call a function in an external library
- libcallnr() idem, returning a number
-
- ==============================================================================
- *41.7* Defining a function
-
- Vim enables you to define your own functions. The basic function declaration
- begins as follows: >
-
- :function {name}({var1}, {var2}, ...)
- : {body}
- :endfunction
- <
- Note:
- Function names must begin with a capital letter.
-
- Let's define a short function to return the smaller of two numbers. It starts
- with this line: >
-
- :function Min(num1, num2)
-
- This tells Vim that the function is named "Min" and it takes two arguments:
- "num1" and "num2".
- The first thing you need to do is to check to see which number is smaller:
- >
- : if a:num1 < a:num2
-
- The special prefix "a:" tells Vim that the variable is a function argument.
- Let's assign the variable smaller the value of the smallest number: >
-
- : if a:num1 < a:num2
- : let smaller = a:num1
- : else
- : let smaller = a:num2
- : endif
-
- The variable "smaller" is a local variable. Variables used inside a function
- are local unless prefixed by something like "g:", "a:", or "s:".
-
- Note:
- To access a global variable from inside a function you must prepend
- "g:" to it. Thus "g:count" inside a function is used for the global
- variable "count", and "count" is another variable, local to the
- function.
-
- You now use the ":return" statement to return the smallest number to the user.
- Finally, you end the function: >
-
- : return smaller
- :endfunction
-
- The complete function definition is as follows: >
-
- :function Min(num1, num2)
- : if a:num1 < a:num2
- : let smaller = a:num1
- : else
- : let smaller = a:num2
- : endif
- : return smaller
- :endfunction
-
- A user defined function is called in exactly the same way as a builtin
- function. Only the name is different. The Min function can be used like
- this: >
-
- :echo Min(5, 8)
-
- Only now will the function be executed and the lines be interpreted by Vim.
- If there are mistakes, like using an undefined variable or function, you will
- now get an error message. When defining the function these errors are not
- detected.
-
- When a function reaches ":endfunction" or ":return" is used without an
- argument, the function returns zero.
-
- To redefine a function that already exists, use the ! for the ":function"
- command: >
-
- :function! Min(num1, num2, num3)
-
-
- USING A RANGE
-
- The ":call" command can be given a line range. This can have one of two
- meanings. When a function has been defined with the "range" keyword, it will
- take care of the line range itself.
- The function will be passed the variables "a:firstline" and "a:lastline".
- These will have the line numbers from the range the function was called with.
- Example: >
-
- :function Count_words() range
- : let n = a:firstline
- : let count = 0
- : while n <= a:lastline
- : let count = count + Wordcount(getline(n))
- : endwhile
- : echo "found " . count . " words"
- :endfunction
-
- You can call this function with: >
-
- :10,30call Count_words()
-
- It will be executed once and echo the number of words.
- The other way to use a line range is by defining a function without the
- "range" keyword. The function will be called once for every line in the
- range, with the cursor in that line. Example: >
-
- :function Number()
- : echo "line " . line(".") . " contains: " . getline(".")
- :endfunction
-
- If you call this function with: >
-
- :10,15call Number()
-
- The function will be called six times.
-
-
- VARIABLE NUMBER OF ARGUMENTS
-
- Vim enables you to define functions that have a variable number of arguments.
- The following command, for instance, defines a function that must have 1
- argument (start) and can have up to 20 additional arguments: >
-
- :function Show(start, ...)
-
- The variable "a:1" contains the first optional argument, "a:2" the second, and
- so on. The variable "a:0" contains the number of extra arguments.
- For example: >
-
- :function Show(start, ...)
- : echohl Title
- : echo "Show is " . a:start
- : echohl None
- : let index = 1
- : while index <= a:0
- : execute 'echon " Arg " . index . " is " . a:' . index
- : let index = index + 1
- : endwhile
- : echo ""
- :endfunction
-
- This uses the ":echohl" command to specify the highlighting used for the
- following ":echo" command. ":echohl None" stops it again. The ":echon"
- command works like ":echo", but doesn't output a line break.
-
-
- LISTING FUNCTIONS
-
- The ":function" command lists the names and arguments of all user-defined
- functions: >
-
- :function
- < function Show(start, ...) ~
- function GetVimIndent()~
- function SetSyn(name) ~
-
- To see what a function does, use its name as an argument for ":function": >
-
- :function Show
- < 1 : echo "Show is " . a:start ~
- 2 : let index = 1 ~
- 3 : while index <= a:0 ~
- 4 : execute 'echo "Arg " . index . " is " . a:' . index ~
- 5 : let index = index + 1 ~
- 6 : endwhile ~
- endfunction ~
-
-
- DEBUGGING
-
- The line number is useful for when you get an error message or when debugging.
- See |debug-scripts| about debugging mode.
- You can also set the 'verbose' option to 12 or higher to see all function
- calls. Set it to 15 or higher to see every executed line.
-
-
- DELETING A FUNCTION
-
- To delete the Show() function: >
-
- :delfunction Show
-
- You get an error when the function doesn't exist.
-
- ==============================================================================
- *41.8* Various remarks
-
- Here is a summary of items that apply to Vim scripts. They are also mentioned
- elsewhere, but form a nice checklist.
-
- The end-of-line character depends on the system. For Unix a single <NL>
- character is used. For MS-DOS, Windows, OS/2 and the like, <CR><LF> is used.
- This is important when using mappings that end in a <CR>. See |:source_crnl|.
-
-
- WHITE SPACE
-
- Blank lines are allowed and ignored.
-
- Leading whitespace characters (blanks and TABs) are always ignored. The
- whitespaces between parameters (e.g. between the 'set' and the 'cpoptions' in the
- example below) are reduced to one blank character and plays the role of a
- separator, the whitespaces after the last (visible) character may or may not
- be ignored depending on the situation, see below.
-
- For a ":set" command involving the "=" (equal) sign, such as in: >
-
- :set cpoptions =aABceFst
-
- The whitespace immediately before the "=" sign is ignored. But there can be
- no whitespace after the "=" sign!
-
- To include a whitespace character in the value of an option, it must be
- escaped by a "\" (backslash) as in the following example: >
-
- :set tags=my\ nice\ file
-
- The same example written as >
-
- :set tags=my nice file
-
- will issue an error, because it is interpreted as: >
-
- :set tags=my
- :set nice
- :set file
-
-
- COMMENTS
-
- The character " (the double quote mark) starts a comment. Everything after
- and including this character until the end-of-line is considered a comment and
- is ignored, except for commands that don't consider comments, as shown in
- examples below. A comment can start on any character position on the line.
-
- There is a little "catch" with comments for some commands. Examples: >
-
- :abbrev dev development " shorthand
- :map <F3> o#include " insert include
- :execute cmd " do it
- :!ls *.c " list C files
-
- The abbreviation 'dev' will be expanded to 'development " shorthand'. The
- mapping of <F3> will actually be the whole line after the 'o# ....' including
- the '" insert include'. The "execute" command will give an error. The "!"
- command will send everything after it to the shell, causing an error for an
- unmatched '"' character.
- There can be no comment after ":map", ":abbreviate", ":execute" and "!"
- commands (there are a few more commands with this restriction). For the
- "map", ":abbreviate" and "execute" commands there is a trick: >
-
- :abbrev dev development|" shorthand
- :map <F3> o#include|" insert include
- :execute cmd |" do it
-
- With the '|' character the command is separated from the next one. And that
- next command is only a comment.
-
- Notice that there is no white space before the '|' in the abbreviation and
- mapping. For these commands, any character until the end-of-line or '|' is
- included. As a consequence of this behavior, you don't always see that
- trailing whitespace is included: >
-
- :map <F4> o#include
-
- To avoid these problems, you can set the 'list' option when editing vimrc
- files.
-
-
- PITFALLS
-
- Even bigger problem arises in the following example: >
-
- :map ,ab o#include
- :unmap ,ab
-
- Here the unmap command will not work, because it tries to unmap ",ab ". This
- does not exist as a mapped sequence. An error will be issued, which is very
- hard to identify, because the ending whitespace character on the 'unmap ,ab '
- is not visible.
-
- And this is the same as what happens when one uses a comment after an 'unmap'
- command: >
-
- :unmap ,ab " comment
-
- Here the comment part will be ignored. However, Vim will try to unmap
- ',ab ', which does not exist. Rewreite it as: >
-
- :unmap ,ab|" comment
-
-
- RESTORING THE VIEW
-
- Sometimes you want to make a change and go back to where cursor was.
- Restoring the relative position would also be nice, so that the same line
- appears at the top of the window.
- This example yanks the current line, puts it above the first line in the
- file and then restores the view: >
-
- map ,p ma"aYHmbgg"aP`bzt`a
-
- What this does: >
- ma"aYHmbgg"aP`bzt`a
- < ma set mark a at cursor position
- "aY yank current line into register a
- Hmb go to top line in window and set mark b there
- gg go to first line in file
- "aP put the yanked line above it
- `b go back to top line in display
- zt position the text in the window as before
- `a go back to saved cursor position
-
-
- PACKAGING
-
- To avoid your function names to interfere with functions that you get from
- others, use this scheme:
- - Prepend a unique string before each function name. I often use an
- abbreviation. For example, "OW_" is used for the option window functions.
- - Put the definition of your functions together in a file. Set a global
- variable to indicate that the functions have been loaded. When sourcing the
- file again, first unload the functions.
- Example: >
-
- " This is the XXX package
-
- if exists("XXX_loaded")
- delfun XXX_one
- delfun XXX_two
- endif
-
- function XXX_one(a)
- ... body of function ...
- endfun
-
- function XXX_two(b)
- ... body of function ...
- endfun
-
- let XXX_loaded = 1
-
- ==============================================================================
- *41.9* Writing a plugin *write-plugin*
-
- You can write a Vim script in such a way that many people can use it. This is
- called a plugin. Vim users can drop your script in their plugin directory and
- use its features right away |add-plugin|.
-
- There are actually two types of plugins:
-
- global plugins: For all types of files.
- filetype plugins: Only for files of a specific type.
-
- In this section the first type is explained. Most items are also relevant for
- writing filetype plugins. The specifics for filetype plugins are in the next
- section |write-filetype-plugin|.
-
-
- NAME
-
- First of all you must choose a name for your plugin. The features provided
- by the plugin should be clear from its name. And it should be unlikely that
- someone else writes a plugin with the same name but which does something
- different. And please limit the name to 8 characters, to avoid problems on
- old Windows systems.
-
- A script that corrects typing mistakes could be called "typecorr.vim". We
- will use it here as an example.
-
- For the plugin to work for everybody, it should follow a few guidelines. This
- will be explained step-by-step. The complete example plugin is at the end.
-
-
- BODY
-
- Let's start with the body of the plugin, the lines that do the actual work: >
-
- 13 iabbrev teh the
- 14 iabbrev otehr other
- 15 iabbrev wnat want
- 16 iabbrev synchronisation
- 17 \ synchronization
- 18 let s:count = 4
-
- The actual list should be much longer, of course.
-
- The line numbers have only been added to explain a few things, don't put them
- in your plugin file!
-
-
- HEADER
-
- You will probably add new corrections to the plugin and soon have several
- versions laying around. And when distributing this file, people will want to
- know who wrote this wonderful plugin and where they can send remarks.
- Therefore, put a header at the top of your plugin: >
-
- 1 " Vim global plugin for correcting typing mistakes
- 2 " Last Change: 2000 Oct 15
- 3 " Maintainer: Bram Moolenaar <Bram@vim.org>
-
-
- LINE CONTINUATION, AVOIDING SIDE EFFECTS
-
- In line 17 above, the line-continuation mechanism is used |line-continuation|.
- Users with 'compatible' set will run into trouble here, they will get an error
- message. We can't just reset 'compatible', because that has a lot of side
- effects. To avoid this, we will set the 'cpoptions' option to its Vim default
- value and restore it later. That will allow the use of line-continuation and
- make the script work for most people. It is done like this: >
-
- 10 let s:save_cpo = &cpo
- 11 set cpo&vim
- ..
- 41 let &cpo = s:save_cpo
-
- We first store the old value of 'cpoptions' in the s:save_cpo variable. At
- the end of the plugin this value is restored.
-
- Notice that a script-local variable is used |s:var|. A global variable could
- already be in use for something else. Always use script-local variables for
- things that are only used in the script.
-
-
- NOT LOADING
-
- It's possible that a user doesn't always want to load this plugin. Or the
- system administrator has dropped it in the system-wide plugin directory, but a
- user has his own plugin he wants to use. Then the user must have a chance to
- disable loading this specific plugin. This will make it possible: >
-
- 5 if exists("loaded_typecorr")
- 6 finish
- 7 endif
- 8 let loaded_typecorr = 1
-
- This also avoids that when the script is loaded twice it would cause error
- messages for redefining functions and cause trouble for autocommands that are
- added twice.
-
-
- MAPPING
-
- Now let's make the plugin more interesting: We will add a mapping that adds a
- correction for the word under the cursor. We could just pick a key sequence
- for this mapping, but the user might already use it for something else. To
- allow the user to define which keys a mapping in a plugin uses, the <Leader>
- item can be used: >
-
- 21 map <unique> <Leader>a <Plug>TypecorrAdd
-
- The "<Plug>TypecorrAdd" thing will do the work, more about that further on.
-
- The user can set the "mapleader" variable to the key sequence that he wants
- this mapping to start with. Thus if the user has done: >
-
- let mapleader = "_"
-
- the mapping will define "_a". If the user didn't do this, the default value
- will be used, which is a backslash. Then a map for "\a" will be defined.
-
- Note that <unique> is used, this will cause an error message if the mapping
- already happened to exist. |:map-<unique>|
-
- But what if the user wants to define his own key sequence? We can allow that
- with this mechanism: >
-
- 20 if !hasmapto('<Plug>TypecorrAdd')
- 21 map <unique> <Leader>a <Plug>TypecorrAdd
- 22 endif
-
- This checks if a mapping to "<Plug>TypecorrAdd" already exists, and only
- defines the mapping from "<Leader>a" if it doesn't. The user then has a
- chance of putting this in his vimrc file: >
-
- map ,c <Plug>TypecorrAdd
-
- Then the mapped key sequence will be ",c" instead of "_a" or "\a".
-
-
- PIECES
-
- If a script gets longer, you often want to break up the work in pieces. You
- can use functions or mappings for this. But you don't want these functions
- and mappings to interfere with the ones from other scripts. For example, you
- could define a function Add(), but another script could try to define the same
- function. To avoid this, we define the function local to the script by
- prepending it with "s:".
-
- We will define a function that adds a new typing correction: >
-
- 29 function s:Add(from, correct)
- 30 let to = input("type the correction for " . a:from . ": ")
- 31 exe ":iabbrev " . a:from . " " . to
- ..
- 35 endfunction
-
- Now we can call the function s:Add() from within this script. If another
- script also defines s:Add(), it will be local to that script and can only
- be called from the script it was defined in. There can also be a global Add()
- function (without the "s:"), which is again another function.
-
- <SID> can be used with mappings. It generates a script ID, which identifies
- the current script. In our typing correction plugin we use it like this: >
-
- 23 noremap <unique> <script> <Plug>TypecorrAdd <SID>Add
- ..
- 27 noremap <SID>Add :call <SID>Add(expand("<cword>"), 1)<CR>
-
- Thus when a user types "\a", this sequence is invoked: >
-
- \a -> <Plug>TypecorrAdd -> <SID>Add -> :call <SID>Add()
-
- If another script would also map <SID>Add, it would get another script ID and
- thus define another mapping.
-
- Note that instead of s:Add() we use <SID>Add() here. That is because the
- mapping is typed by the user, thus outside of the script. The <SID> is
- translated to the script ID, so that Vim knows in which script to look for
- the Add() function.
-
- This is a bit complicated, but it's required for the plugin to work together
- with other plugins. The basic rule is that you use <SID>Add() in mappings and
- s:Add() in other places (the script itself, autocommands, user commands).
-
- We can also add a menu entry to do the same as the mapping: >
-
- 25 noremenu <script> Plugin.Add\ Correction <SID>Add
-
- The "Plugin" menu is recommended for adding menu items for plugins. In this
- case only one item is used. When adding more items, creating a submenu is
- recommended. For example, "Plugin.CVS" could be used for a plugin that offers
- CVS operations "Plugin.CVS.checkin", "Plugin.CVS.checkout", etc.
-
- Note that in line 27 ":noremap" is used to avoid that any other mappings cause
- trouble. Someone may have remapped ":call", for example. In line 23 we also
- use ":noremap", but we do want "<SID>Add" to be remapped. This is why
- "<script>" is used here. This only allows mappings which are local to the
- script. |:map-<script>| The same is done in line 25 for ":noremenu".
- |:menu-<script>|
-
-
- <SID> AND <Plug>
-
- Both <SID> and <Plug> are used to avoid that mappings of typed keys interfere
- with mappings that are only to be used from other mappings. Note the
- difference between using <SID> and <Plug>:
-
- <Plug> is visible outside of the script. It is used for mappings which the
- user might want to map a key sequence to. <Plug> is a special code
- that a typed key will never produce.
- To make it very unlikely that other plugins use the same sequence of
- characters, use this structure: <Plug> scriptname mapname
- In our example the scriptname is "Typecorr" and the mapname is "Add".
- This results in "<Plug>TypecorrAdd". Only the first character of
- scriptname and mapname is uppercase, so that we can see where mapname
- starts.
-
- <SID> is the script ID, a unique identifier for a script.
- Internally Vim translates <SID> to "<SNR>123_", where "123" can be any
- number. Thus a function "<SID>Add()" will have a name "<SNR>11_Add()"
- in one script, and "<SNR>22_Add()" in another. You can see this if
- you use the ":function" command to get a list of functions. The
- translation of <SID> in mappings is exactly the same, that's how you
- can call a script-local function from a mapping.
-
-
- USER COMMAND
-
- Now let's add a user command to add a correction: >
-
- 37 if !exists(":Correct")
- 38 command -nargs=1 Correct :call s:Add(<q-args>, 0)
- 39 endif
-
- The user command is defined only if no command with the same name already
- exists. Otherwise we would get an error here. Overriding the existing user
- command with ":command!" is not a good idea, this would probably make the user
- wonder why the command he defined himself doesn't work. |:command|
-
-
- SCRIPT VARIABLES
-
- When a variable starts with "s:" it is a script variable. It can only be used
- inside a script. Outside the script it's not visible This avoids trouble
- with using the same variable name in different scripts. The variables will be
- kept as long as Vim is running. And the same variables are used when sourcing
- the same script again. |s:var|
-
- The fun is that these variables can also be used in functions, autocommands
- and user commands that are defined in the script. In our example we can add
- a few lines to count the number of corrections: >
-
- 18 let s:count = 4
- ..
- 29 function s:Add(from, correct)
- ..
- 33 let s:count = s:count + 1
- 34 echo s:count . " corrections now"
- 35 endfunction
-
- First s:count is initialized to 4 in the script itself. When later the
- s:Add() function is called, it increments s:count. It doesn't matter from
- where the function was called, since it has been defined in the script, it
- will use the local variables from this script.
-
-
- THE RESULT
-
- Here is the resulting complete example: >
-
- 1 " Vim global plugin for correcting typing mistakes
- 2 " Last Change: 2000 Oct 15
- 3 " Maintainer: Bram Moolenaar <Bram@vim.org>
- 4
- 5 if exists("loaded_typecorr")
- 6 finish
- 7 endif
- 8 let loaded_typecorr = 1
- 9
- 10 let s:save_cpo = &cpo
- 11 set cpo&vim
- 12
- 13 iabbrev teh the
- 14 iabbrev otehr other
- 15 iabbrev wnat want
- 16 iabbrev synchronisation
- 17 \ synchronization
- 18 let s:count = 4
- 19
- 20 if !hasmapto('<Plug>TypecorrAdd')
- 21 map <unique> <Leader>a <Plug>TypecorrAdd
- 22 endif
- 23 noremap <unique> <script> <Plug>TypecorrAdd <SID>Add
- 24
- 25 noremenu <script> Plugin.Add\ Correction <SID>Add
- 26
- 27 noremap <SID>Add :call <SID>Add(expand("<cword>"), 1)<CR>
- 28
- 29 function s:Add(from, correct)
- 30 let to = input("type the correction for " . a:from . ": ")
- 31 exe ":iabbrev " . a:from . " " . to
- 32 if a:correct | exe "normal viws\<C-R>\" \b\e" | endif
- 33 let s:count = s:count + 1
- 34 echo s:count . " corrections now"
- 35 endfunction
- 36
- 37 if !exists(":Correct")
- 38 command -nargs=1 Correct :call s:Add(<q-args>, 0)
- 39 endif
- 40
- 41 let &cpo = s:save_cpo
-
- Line 32 wasn't explained yet. It applies the new correction to the word under
- the cursor. The |:normal| command is used to use the new abbreviation. Note
- that mappings and abbreviations are expanded here, even though the function
- was called from a mapping defined with ":noremap".
-
-
- DOCUMENTATION
- *write-local-help*
- It's a good idea to also write some documentation for your plugin. Especially
- when its behavior can be changed by the user. See |add-local-help| for how
- they are installed.
-
- Here is a simple example for a plugin help file, called "typecorr.txt": >
-
- 1 *typecorr.txt* Plugin for correcting typing mistakes
- 2
- 3 If you make typing mistakes, this plugin will have them corrected
- 4 automatically.
- 5
- 6 There are currently only a few corrections. Add your own if you like.
- 7
- 8 Mappings:
- 9 <Leader>a or <Plug>TypecorrAdd
- 10 Add a correction for the word under the cursor.
- 11
- 12 Commands:
- 13 :Correct {word}
- 14 Add a correction for {word}.
- 15
- 16 *typecorr-settings*
- 17 This plugin doesn't have any settings.
-
- The first line is actually the only one for which the format matters. It will
- be extracted from the help file to be put in the "LOCAL ADDITIONS:" section of
- help.txt. The first "*" must be in the first column of the first line.
-
- You can add more tags inside ** in your help file. But be careful not to use
- existing help tags. You would probably use the name of your plugin in most of
- them, like "typecorr-settings" in the example.
-
- Using references to other parts of the help in || is recommended. This makes
- it easy for the user to find associated help.
-
-
- SUMMARY *plugin-special*
-
- Summary of special things to use in a plugin:
-
- s:name Variables local to the script.
-
- <SID> Script-ID, used for mappings and functions local to
- the script.
-
- hasmapto() Function to test if the user already defined a mapping
- for functionality the script offers.
-
- <Leader> Value of "mapleader", which the user defines as the
- keys that plugin mappings start with.
-
- :map <unique> Give a warning if a mapping already exists.
-
- :noremap <script> Use only mappings local to the script, not global
- mappings.
-
- exists(":Cmd") Check if a user command already exists.
-
- ==============================================================================
- *41.10* Writing a filetype plugin *write-filetype-plugin* *ftplugin*
-
- A filetype plugin is like a global plugin, except that it sets options and
- defines mappings for the current buffer only. See |add-filetype-plugin| for
- how this type of plugin is used.
-
- First read the section on global plugins above |41.7|. All that is said there
- also applies to filetype plugins. There are a few extras, which are explained
- here. The essential thing is that a filetype plugin should only have an
- effect on the current buffer.
-
-
- DISABLING
-
- If you are writing a filetype plugin to be used by many people, they need a
- chance to disable loading it. Put this at the top of the plugin: >
-
- " Only do this when not done yet for this buffer
- if exists("b:did_ftplugin")
- finish
- endif
- let b:did_ftplugin = 1
-
- This also needs to be used to avoid that the same plugin is executed twice for
- the same buffer (happens when using an ":edit" command without arguments).
-
- Now users can disable loading the default plugin completely by making a filetype
- plugin with only this line: >
-
- let b:did_ftplugin = 1
-
- This does require that the filetype plugin directory comes before $VIMRUNTIME
- in 'runtimepath'!
-
- If you do want to use the default plugin, but overrule one of the settings,
- you can make a filetype plugin like this: >
-
- source $VIMRUNTIME/ftplugin/vim.vim
- set textwidth=70
-
- This first loads the default filetype plugin to get all its settings. Then
- the value for the 'textwidth' option is changed to "70". Note that the
- default plugin will have set "b:did_ftplugin", thus when it's sourced later,
- it won't do anything.
-
-
- OPTIONS
-
- To make sure the filetype plugin only affects the current buffer use the >
- :setlocal
- command to set options. And only set options which are local to a buffer (see
- the help for the option to check that). When using |:setlocal| for global
- options or options local to a window, the value will change for many buffers,
- and that is not what a filetype plugin should do.
-
- When an option has a value that is a list of flags or items, consider using
- "+=" and "-=" to keep the existing value. Be aware that the user may have
- changed an option value already. First resetting to the default value and
- then changing it often a good idea. Example: >
- :setlocal formatoptions& formatoptions+=ro
-
-
- MAPPINGS
-
- To make sure mappings will only work in the current buffer use the >
- :map <buffer>
- command. This needs to be combined with the two-step mapping explained above.
- An example of how to define funcionality in a filetype plugin: >
-
- if !hasmapto('<Plug>JavaImport')
- map <buffer> <unique> <LocalLeader>i <Plug>JavaImport
- endif
- noremap <buffer> <unique> <Plug>JavaImport oimport ""<Left><Esc>
-
- |hasmapto()| is used to check if the user has already defined a map to
- <Plug>JavaImport. If not, then the filetype plugin defines the default
- mapping. This starts with |<LocalLeader>|, which allows the user to select
- the key(s) he wants filetype plugin mappings to start with. The default is a
- backslash.
- "<unique>" is used to give an error message if the mapping already exists or
- overlaps with an existing mapping.
- |:noremap| is used to avoid that any other mappings that the user has defined
- interferes. You might want to use ":noremap <script>" to allow remapping
- mappings defined in this script that start with <SID>.
-
- The user must have a chance to disable the mappings in a filetype plugin,
- without disabling everything. Here is an example of how this is done for a
- plugin for the mail filetype: >
-
- " Add mappings, unless the user didn't want this.
- if !exists("no_plugin_maps") && !exists("no_mail_maps")
- " Quote text by inserting "> "
- if !hasmapto('<Plug>MailQuote')
- vmap <buffer> <LocalLeader>q <Plug>MailQuote
- nmap <buffer> <LocalLeader>q <Plug>MailQuote
- endif
- vnoremap <buffer> <Plug>MailQuote :s/^/> /<CR>
- nnoremap <buffer> <Plug>MailQuote :.,$s/^/> /<CR>
- endif
-
- Two global variables are used:
- no_plugin_maps disables mappings for all filetype plugins
- no_mail_maps disables mappings for a specific filetype
-
-
- USER COMMANDS
-
- To add a user command for a specific file type, so that it can only be used in
- one buffer, use the "-buffer" argument to |:command|. Example: >
-
- :command -buffer Make make %:r.s
-
-
- VARIABLES
-
- A filetype plugin will be sourced for each buffer of the type it's for. Local
- script variables |s:var| will be shared between all invocations. Use local
- buffer variables |b:var| if you want a variable specifically for one buffer.
-
-
- FUNCTIONS
-
- When defining a function, this only needs to be done once. But the filetype
- plugin will be sourced every time a file with this filetype will be opened.
- This construct make sure the function is only defined once: >
-
- :if !exists("*s:Func")
- : function s:Func(arg)
- : ...
- : endfunction
- :endif
- <
-
- SUMMARY *ftplugin-special*
-
- Summary of special things to use in a filetype plugin:
-
- <LocalLeader> Value of "maplocalleader", which the user defines as
- the keys that filetype plugin mappings start with.
-
- :map <buffer> Define a mapping local to the buffer.
-
- :noremap <script> Only remap mappings defined in this script that start
- with <SID>.
-
- :setlocal Set an option for the current buffer only.
-
- :command -buffer Define a user command local to the buffer.
-
- exists("*s:Func") Check if a function was already defined.
-
- Also see |plugin-special|, the special things used for all plugins.
-
- ==============================================================================
- *41.11* Writing a compiler plugin *write-compiler-plugin*
-
- A compiler plugin sets options for use with a specific compiler. The user can
- load it with the |:compiler| command. The main use is to set the
- 'errorformat' and 'makeprg' options.
-
- The only special item about these files is a mechanism to allow a user to
- overrule or add to the default file. The default files start with: >
-
- :if exists("current_compiler")
- : finish
- :endif
- :let current_compiler = "mine"
-
- When you write a compiler file and put it in your personal runtime directory
- (e.g., ~/.vim/runtime/compiler for Unix), you set the "current_compiler"
- variable to make the default file skip the settings.
-
- When you write a compiler plugin for the Vim distribution or for a system-wide
- runtime directory, use the mechanism mentioned above. When
- "current_compiler" was already set by a user plugin nothing will be done.
-
- When you write a compiler plugin to overrule settings from a default plugin,
- don't check "current_compiler". This plugin is supposed to be loaded
- last, thus it should be in a directory at the end of 'runtimepath'. For Unix
- that could be ~/.vim/runtime/after/compiler.
-
- ==============================================================================
-
- Next chapter: |usr_42.txt| Add new menus
-
- Copyright: see |manual-copyright| vim:tw=78:ts=8:ft=help:norl:
-